package cn.falcon.fmobi.console.controller;

import cn.falcon.fmobi.biz.common.Constant;
import cn.falcon.fmobi.biz.exception.PromotionPlanValidateException;
import cn.falcon.fmobi.biz.service.AdvertiserPlatformAuditService;
import cn.falcon.fmobi.biz.service.FmobiCampaignService;
import cn.falcon.fmobi.biz.service.PromotionPlanService;
import cn.falcon.fmobi.console.common.RestfulJsonModelAndView;
import cn.falcon.fmobi.console.common.Result;
import cn.falcon.fmobi.console.constant.ParamConstant;
import cn.falcon.fmobi.console.constant.UrlConstant;
import cn.falcon.fmobi.console.constant.UserRolePermission;
import cn.falcon.fmobi.console.exception.CallBackException;
import cn.falcon.fmobi.console.exception.ParamValidateException;
import cn.falcon.fmobi.console.requestparam.Query;
import cn.falcon.fmobi.dao.enumration.PromotionPlanType;
import cn.falcon.fmobi.dao.model.*;
import cn.falcon.fmobi.dao.po.AdvertiserPlatformAudit;
import cn.falcon.fmobi.dao.po.Campaign;
import cn.falcon.fmobi.dao.po.PromotionPlan;
import cn.falcon.marketing.api.enumeration.Operator;
import cn.falcon.marketing.api.model.FilteringStruct;
import cn.falcon.marketing.api.model.fund.RealtimeCost;
import cn.falcon.marketing.api.model.fund.RealtimeCostStructResult;
import cn.falcon.marketing.api.service.fund.IFundService;
import cn.falcon.marketing.api.util.JsonUtil;
import cn.falcon.marketing.api.util.ValidateUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

import static cn.falcon.fmobi.console.common.Result.ERR_INVALID_LENGTH;
import static cn.falcon.fmobi.console.constant.ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX;
import static cn.falcon.fmobi.console.constant.ParamConstant.PROMOTION_PLAN_UNIT_CONVERSION;

/**
 * Created by haojie.zhang
 * Time 2017/10/17.
 */
@Controller
@RequestMapping(UrlConstant.PROMOTION_PLAN)
public class PromotionPlanCtrl extends BaseCtrl {

    @Autowired
    private PromotionPlanService promotionPlanService;

    @Autowired
    private IFundService fundService;

    @Autowired
    private AdvertiserPlatformAuditService advertiserPlatformAuditService;

    @Autowired
    private FmobiCampaignService fmobiCampaignService;

    /**
     * 新建推广计划接口
     * @param campaignId
     * @param addPromotionPlanVo
     * @param session
     * @return
     * @throws ParamValidateException
     * @throws UnsupportedEncodingException
     * @throws PromotionPlanValidateException
     */
    @RequestMapping(value = "/addPromotionPlan", method = {RequestMethod.POST})
    public ModelAndView addAudience(@PathVariable("campaignId") Integer campaignId, @RequestBody AddPromotionPlanVo addPromotionPlanVo, HttpSession session)
            throws ParamValidateException, UnsupportedEncodingException, PromotionPlanValidateException {
        addPromotionPlanVo.setCampaignId(campaignId);
        //设置溢价
        addPromotionPlanVo.setDailyBudget(addPromotionPlanVo.getDailyBudget().multiply(readUserRates(session)));
        //参数验证
        this.validateAddPromotionPlanVo(addPromotionPlanVo, session);

        Integer advertiserId = getLoginUser(session) != null ? getLoginUser(session).getAdvertiserId() : null;
        // 查询代理商id
        Integer agentId = getLoginUser(session) != null ? getLoginUser(session).getAgentId() : null;
        //广告主权限
        addPromotionPlanVo.setAccountId(this.jurisdiction(advertiserId, agentId, campaignId));

        promotionPlanService.addPromotionPlan(addPromotionPlanVo);
        return RestfulJsonModelAndView.buildJsonModelAndView();
    }

    /**
     * 权限设置
     *
     * @param advertiserId
     * @param agentId
     * @param campaignId
     * @return
     */
    public Integer jurisdiction(Integer advertiserId, Integer agentId, Integer campaignId) {
        if (null == agentId || 0 == agentId) {
            AdvertiserPlatformAudit advertiserPlatformAudit
                    = advertiserPlatformAuditService.selectAdvertiserPlatformAuditByPlatformIdAndAdvertiserId(Constant.PLATFORM_ID_TENCENT, advertiserId);

            return advertiserPlatformAudit.getPlatformAdvertiserId();
        } else {
            //根据我们这边广告主id查询对应广告主id
            Campaign campaign = fmobiCampaignService.getCampaign(campaignId);
            AdvertiserPlatformAudit advertiserPlatformAudit
                    = advertiserPlatformAuditService.selectAdvertiserPlatformAuditByPlatformIdAndAdvertiserId(Constant.PLATFORM_ID_TENCENT, campaign.getAdvertiserId());
            return advertiserPlatformAudit.getPlatformAdvertiserId();
        }
    }

    /**
     * 日限消耗更新
     * @param campaignId
     * @param updateDayBudgetVo
     * @param session
     * @return
     * @throws UnsupportedEncodingException
     * @throws ParamValidateException
     */
    @RequestMapping(value = "/updateDayBudget", method = {RequestMethod.POST})
    public ModelAndView updateStatus(@PathVariable("campaignId") Integer campaignId, @RequestBody UpdateDayBudgetVo updateDayBudgetVo, HttpSession session)
            throws UnsupportedEncodingException, ParamValidateException {
        //经过溢价之后的最小值
        BigDecimal budgetMix=new BigDecimal(ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX).divide(readUserRates(session),4);
        //设置溢价
        updateDayBudgetVo.setDayBudget(updateDayBudgetVo.getDayBudget().multiply(readUserRates(session)));
        //设置广告主权限
        Integer advertiserId = getLoginUser(session) != null ? getLoginUser(session).getAdvertiserId() : null;
        // 查询代理商id
        Integer agentId = getLoginUser(session) != null ? getLoginUser(session).getAgentId() : null;

        updateDayBudgetVo.setAccountId(this.jurisdiction(advertiserId, agentId, campaignId));

        //获取对应推广计划id
        PromotionPlan promotionPlan = promotionPlanService.getPromotionPlan(updateDayBudgetVo.getId());
        if (promotionPlan.getPlatformPromotionPlanId() == null) {
            throw new CallBackException(PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_INVALID_CAMPAIGN_ID.getValue(),
                    PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_INVALID_CAMPAIGN_ID.getDesc());
        }
        updateDayBudgetVo.setPlatformPromotionPlanId(promotionPlan.getPlatformPromotionPlanId());
        // 此处需要做溢价处理
        // 做日限消耗限制
        Integer cost = (this.cost(updateDayBudgetVo.getAccountId(), promotionPlan.getPlatformPromotionPlanId()) / ParamConstant.PROMOTION_PLAN_UNIT_CONVERSION)
                + ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX;
        // 日算限额不为null and 日算限额修改
        if (updateDayBudgetVo.getDayBudget() != null && updateDayBudgetVo.getDayBudget().intValue() != promotionPlan.getDayBudget().intValue()) {
            if(updateDayBudgetVo.getDayBudget().intValue()<ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX){
                throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "", "每次修改幅度不能低于 " + budgetMix + "00 分（ " + budgetMix + " 元，单位为人民币 ）");
            }
            if (updateDayBudgetVo.getDayBudget().intValue() > (promotionPlan.getDayBudget().intValue() - cost)
                    && updateDayBudgetVo.getDayBudget().intValue() < (promotionPlan.getDayBudget().intValue() + cost)) {
                throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "", "每次修改幅度不能低于该计划今日已消耗金额加上" + budgetMix + "元");
            }
        }
        promotionPlanService.updateDayBudget(updateDayBudgetVo);
        return RestfulJsonModelAndView.buildJsonModelAndView();
    }

    /**
     * 快捷修改状态
     * @param campaignId
     * @param updateStatusVo
     * @param session
     * @return
     * @throws UnsupportedEncodingException
     * @throws ParamValidateException
     */
    @RequestMapping(value = "/updateStatus", method = {RequestMethod.POST})
    public ModelAndView updateDayBudget(@PathVariable("campaignId") Integer campaignId, @RequestBody UpdateStatusVo updateStatusVo, HttpSession session)
            throws UnsupportedEncodingException, ParamValidateException {
        //设置广告主权限
        Integer advertiserId = getLoginUser(session) != null ? getLoginUser(session).getAdvertiserId() : null;
        // 查询代理商id
        Integer agentId = getLoginUser(session) != null ? getLoginUser(session).getAgentId() : null;

        updateStatusVo.setAccountId(this.jurisdiction(advertiserId, agentId, campaignId));

        promotionPlanService.updateStatus(updateStatusVo);
        return RestfulJsonModelAndView.buildJsonModelAndView();
    }

    /**
     * 包类型
     *
     * @return
     */
    @RequestMapping("/promotionPlanType")
    public ModelAndView numberType() {
        List<NumberTypeModel> param = new ArrayList<>();
        NumberTypeModel numberTypeModel;
        for (PromotionPlanType promotionPlanType : PromotionPlanType.values()) {
            numberTypeModel = new NumberTypeModel();
            numberTypeModel.setName(promotionPlanType.getValue());
            numberTypeModel.setId(String.valueOf(promotionPlanType.getName()));
            param.add(numberTypeModel);
        }
        return RestfulJsonModelAndView.buildJsonModelAndView(param);
    }


    /**
     * 推广计划查询接口
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/getPromotionPlan", method = {RequestMethod.GET})
    public ModelAndView getPromotionPlan(@RequestParam Integer id, HttpSession session) {
        Map<String, Object> param = new HashMap<>();
        param.put("premium", readUserRates(session));
        param.put("id", id);
        PromotionPlan promotionPlan = promotionPlanService.getPromotionPlan(param);
        return RestfulJsonModelAndView.buildJsonModelAndView(promotionPlan);
    }

    /**
     * 推广计划更新接口
     * @param campaignId
     * @param session
     * @param updatePromotionPlanVo
     * @return
     * @throws PromotionPlanValidateException
     * @throws ParamValidateException
     * @throws UnsupportedEncodingException
     */
    @RequestMapping(value = "/updatePromotionPlan", method = {RequestMethod.POST})
    public ModelAndView update(@PathVariable("campaignId") Integer campaignId,HttpSession session,@RequestBody UpdatePromotionPlanVo updatePromotionPlanVo)
            throws PromotionPlanValidateException,ParamValidateException, UnsupportedEncodingException{
        //经过溢价之后的最小值
        BigDecimal budgetMix=new BigDecimal(ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX).divide(readUserRates(session),4);

        updatePromotionPlanVo.setCampaignId(campaignId);
        //设置溢价
        updatePromotionPlanVo.setDailyBudget(updatePromotionPlanVo.getDailyBudget().multiply(readUserRates(session)));
        //设置广告主权限
        Integer advertiserId = getLoginUser(session) != null ? getLoginUser(session).getAdvertiserId() : null;
        // 查询代理商id
        Integer agentId = getLoginUser(session) != null ? getLoginUser(session).getAgentId() : null;

        updatePromotionPlanVo.setAccountId(this.jurisdiction(advertiserId, agentId, campaignId));

        //获取对应推广计划id
        PromotionPlan promotionPlan = promotionPlanService.getPromotionPlan(updatePromotionPlanVo.getId());

        if (promotionPlan.getPlatformPromotionPlanId() == null) {
            throw new CallBackException(PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_INVALID_CAMPAIGN_ID.getValue(),
                    PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_INVALID_CAMPAIGN_ID.getDesc());
        }
        updatePromotionPlanVo.setPlatformPromotionPlanId(promotionPlan.getPlatformPromotionPlanId());

        Integer cost = (this.cost(updatePromotionPlanVo.getAccountId(), promotionPlan.getPlatformPromotionPlanId()) / ParamConstant.PROMOTION_PLAN_UNIT_CONVERSION)
                + ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX;

        if (null != updatePromotionPlanVo.getDailyBudget() && null != promotionPlan.getDayBudget()
                && updatePromotionPlanVo.getDailyBudget().intValue() != promotionPlan.getDayBudget().intValue()) {
            if (updatePromotionPlanVo.getDailyBudget().intValue() < ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX) {
                throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "", "每次修改幅度不能低于 " + budgetMix + "00 分（ " + budgetMix + " 元，单位为人民币 ）");
            }

            if (updatePromotionPlanVo.getDailyBudget().intValue() > (promotionPlan.getDayBudget().intValue() - cost)
                    && updatePromotionPlanVo.getDailyBudget().intValue() < (promotionPlan.getDayBudget().intValue() + cost)) {
                throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "", "每次修改幅度不能低于该计划今日已消耗金额加上" + budgetMix + "元");
            }
        }
        //验证参数
        this.validateUpdatePromotionPlanVo(updatePromotionPlanVo, session);

        promotionPlanService.UpdatePromotionPlan(updatePromotionPlanVo);
        return RestfulJsonModelAndView.buildJsonModelAndView();
    }

    /**
     * 获取消耗数据
     * @param accountId
     * @param campaignId
     * @return
     */
    public Integer cost(Integer accountId,Integer campaignId){
        RealtimeCost realtimeCost = new RealtimeCost();
        realtimeCost.setAccount_id(accountId);
        FilteringStruct[] filteringStructs = new FilteringStruct[1];

        FilteringStruct filteringStruct = new FilteringStruct();
        filteringStruct.setField("campaign_id");
        filteringStruct.setOperator(Operator.EQUALS);
        filteringStruct.setValues(new String[]{String.valueOf(campaignId)});
        filteringStructs[0] = filteringStruct;
        realtimeCost.setFiltering_struct(JsonUtil.toJson(filteringStructs));
        realtimeCost.setDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        realtimeCost.setLevel("CAMPAIGN");
        List<RealtimeCostStructResult> resultList = fundService.realtimeCostGet(realtimeCost,false);
        for (RealtimeCostStructResult realtimeCostStructResult : resultList) {
                return realtimeCostStructResult.getCost();
        }
        return 0;
    }

    /**
     * 更新参数验证
     * @param updatePromotionPlanVo
     * @throws PromotionPlanValidateException
     * @throws ParamValidateException
     * @throws UnsupportedEncodingException
     */
    public void validateUpdatePromotionPlanVo(UpdatePromotionPlanVo updatePromotionPlanVo,HttpSession session)
            throws PromotionPlanValidateException,ParamValidateException,UnsupportedEncodingException{
        //经过溢价之后的最大值
        BigDecimal budgetMax=new BigDecimal(ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MAX).divide(readUserRates(session),4);
        //经过溢价之后的最小值
        BigDecimal budgetMix=new BigDecimal(ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX).divide(readUserRates(session),4);

        int resultName = promotionPlanService.getName(updatePromotionPlanVo.getCampaignId(), updatePromotionPlanVo.getCampaignName(),updatePromotionPlanVo.getId());

        if (resultName != 0) {
            throw new CallBackException(PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_NAME_REPEAT.getValue()
                    ,PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_NAME_REPEAT.getDesc());
        }
        // 获取推广计划信息
        PromotionPlan promotionPlan = promotionPlanService.getPromotionPlan(updatePromotionPlanVo.getId());

        //名称不能为null
        if(StringUtils.isEmpty(updatePromotionPlanVo.getCampaignName())){
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "promotionPlanName", "Result.err.miss.parameter");
        }
        //名称长度限制
        if (ValidateUtil.checkStrByteLengthMoreThan(updatePromotionPlanVo.getCampaignName(), ParamConstant.PROMOTION_PLAN_CAMPAIGN_NAME_LENGTH)) {
            throw new ParamValidateException(ERR_INVALID_LENGTH, "promotionPlanName", "Result.err.invalid.length");
        }
        if (promotionPlan.getType() != 2) {
            if (StringUtils.isEmpty(String.valueOf(updatePromotionPlanVo.getDailyBudget()))) {
                throw new CallBackException(PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_LENGTH_IS_NOT_LEGAL.getValue()
                        ,PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_LENGTH_IS_NOT_LEGAL.getDesc());
            }
            if (updatePromotionPlanVo.getDailyBudget().intValue() < ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX
                    || updatePromotionPlanVo.getDailyBudget().intValue() > ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MAX) {
                throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "", "预算日限不在" + budgetMix + "~" + budgetMax + "之间");
            }
        }else{
            if (null != updatePromotionPlanVo.getDailyBudget() && updatePromotionPlanVo.getDailyBudget().intValue() < ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX
                    || updatePromotionPlanVo.getDailyBudget().intValue() > ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MAX) {
                throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "", "预算日限不在" + budgetMix + "~" + budgetMax + "之间");
            }
        }
    }

    /**
     * 参数验证
     * @param addPromotionPlanVo
     * @throws PromotionPlanValidateException
     * @throws ParamValidateException
     * @throws UnsupportedEncodingException
     */
    public void validateAddPromotionPlanVo(AddPromotionPlanVo addPromotionPlanVo,HttpSession session)
            throws PromotionPlanValidateException,ParamValidateException, UnsupportedEncodingException {
        //经过溢价之后的最大值
        BigDecimal budgetMax=new BigDecimal(ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MAX).divide(readUserRates(session),4);
        //经过溢价之后的最小值
        BigDecimal budgetMix=new BigDecimal(ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX).divide(readUserRates(session),4);

        //判断推广计划名称是否重复
        int resultName = promotionPlanService.getName(addPromotionPlanVo.getCampaignId(), addPromotionPlanVo.getCampaignName(),null);

        if (resultName > 0) {
            throw new CallBackException(PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_NAME_REPEAT.getValue()
                    ,PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_NAME_REPEAT.getDesc());
        }
        //名称不能为null
        if(StringUtils.isEmpty(addPromotionPlanVo.getCampaignName())){
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "campaignName", "Result.err.miss.parameter");
        }
        //名称长度限制
        if (ValidateUtil.checkStrByteLengthMoreThan(addPromotionPlanVo.getCampaignName(), ParamConstant.PROMOTION_PLAN_CAMPAIGN_NAME_LENGTH)) {
            throw new ParamValidateException(ERR_INVALID_LENGTH, "campaignName", "Result.err.invalid.length");
        }
        //2微信朋友圈时不能填
        if (addPromotionPlanVo.getCampaignType().equals(2)) {
            if (StringUtils.isEmpty(String.valueOf(addPromotionPlanVo.getDailyBudget()))) {
                throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "dailyBudget", "Result.err.miss.parameter");
            }
        } else {

            //每日预算限额
            if (StringUtils.isEmpty(String.valueOf(addPromotionPlanVo.getDailyBudget()))) {
                throw new CallBackException(PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_LENGTH_IS_NOT_LEGAL.getValue()
                        ,PromotionPlanValidateException.ErrorCode.PROMOTION_PLAN_LENGTH_IS_NOT_LEGAL.getDesc());
            }
            // 注意这里进行了溢价修改（这里传过来的是已经经过溢价的）
            if (addPromotionPlanVo.getDailyBudget().intValue() < ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MIX
                    || addPromotionPlanVo.getDailyBudget().intValue() > ParamConstant.PROMOTION_PLAN_DAILY_BUDGET_MAX) {
                throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "", "预算日限不在" + budgetMix + "~" + budgetMax + "之间");
            }
        }

    }

    /**
     * 推广计划分页查询接口
     * @param campaignId
     * @param query
     * @return
     * @throws ParamValidateException
     */
    @RequestMapping(value = "/selectPromotionPlan", method = {RequestMethod.GET})
    public ModelAndView selectPromotionPlan(@PathVariable("campaignId") Integer campaignId,Query query,HttpSession session)
            throws ParamValidateException {
        if (null == query.getStartDate() || null == query.getEndDate()) {
            throw new ParamValidateException(Result.ERR_MISS_PARAMETER, "startDate、endDate", "Result.err.miss.parameter");
        }
        if (query.getStartDate().getTime() > query.getEndDate().getTime()) {
            throw new ParamValidateException(Result.ERR_INVALID_PARAMETER, "startDate、endDate", "Result.err.invalid.parameter");
        }
        Map<String,Object> param = query.getSearch();
        param.put("campaignId",campaignId);
        param.put("advertiserId",this.getActorId(UserRolePermission.USER_ROLE_ADVERTISER));
        param.put("agentId",this.getActorId(UserRolePermission.USER_ROLE_AGENT));
        param.put("promotionPlanId",query.getPromotionPlanId());
        param.put("premium",readUserRates(session));
        return RestfulJsonModelAndView.buildJsonModelAndView(promotionPlanService.listPage(param,query.getPageInfo()));
    }

}
